`timescale 1ns / 1ps
`include "top_define.v"
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer:xzh 
// 
// Create Date: 2020/08/25 17:03:21
// Design Name: 
// Module Name: receive_schedule_new
// Project Name: 100G_NP
// Target Devices: 
// Tool Versions: 
// Description: 100GNP_½ÓÊÜµ÷¶È,¸´ÖÆÈý·Ö¶ÔÓ¦ÈýÂ·,³õÊ¼°æ±¾,,¶Ë¿ÚºÅÔÝ¶¨ÎªËÄÎ»
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
module receive_schedule (
  input clk,
  input rst_n,
  input [9:0]ram_2p_cfg_register,
  input access_fail , //·ÃÎÊÊ§°Ü
  //******************·Ö×é´¦Àí******************************
  input in_buf_val                   ,  //×´Ì¬»úÌø×ª
  output reg wr_gnt                  ,  //µ÷¶È¿ªÊ¼
  input multicast                    ,  //×é²¥²é±í  
  //ÐÅÏ¢FIFO
  (*mark_debug = "true"*)input        frame_info_fifo_empty ,
  (*mark_debug = "true"*)output reg   frame_info_fifo_rden  ,
  input[31:0]  frame_info_fifo_o     ,
  ////|[31:30]reserve| |[29]insert_flag| |[28:25]insert_port| |[24:23]¸´ÖÆÖØ¶¨Ïò| |[22]flow_en| |[21:15] flow_num| |[14] valid| |[13:11] pri| |[10:0] len| | 
  
  //ÓÃÓÚ²é±í
  input [47:0] sou_addr              ,
  input [47:0] des_addr              ,
  input [3:0]  sou_id                , //Ô´¶Ë¿ÚºÅ
  input [128:0] ip_src_addr          , //ÐÂÔöÊä³öipv4/v6Ä¿µÄµØÖ·/Ô´µØÖ·
  //input [128:0] ip_des_addr          , //ÐÂÔöÊä³öipv4/v6Ä¿µÄµØÖ·/Ô´µØÖ·,ÔÝÊ±ÎÞÓÃ

  //******************µ¥²¥²é±í******************************
  output wire [47:0] mac_sour  ,
  (*mark_debug = "true"*)output wire [3:0]  port_sour ,
  output wire [47:0] mac_dest  , 
  input  uni_busy              ,  
  output /*reg */uni_addr_en       ,
  input [3:0] uni_outport      ,
  (*mark_debug = "true"*)input uni_outport_en         ,
  input uni_lookup_fail        ,
  input unicam_init_done       ,
  
  //******************×é²¥²é±í******************************
  input  multi_busy               ,
  output /*reg */multi_addr_en        ,
  input [3:0] multi_outport       ,  
  input  multi_outport_en         ,
  output wire [128:0]  multi_ip_src_addr   ,
  input multicam_init_done        ,
  
  //µ÷¶È½á¹ûfifo
  (*mark_debug = "true"*)output wire [31:0] rx_fifo_data    ,
  (*mark_debug = "true"*)output wire rx_fifo_wrreq          ,
  input rx_fifo_full               ,    //Íâ²¿fifoÂú±êÖ¾£¬¾­¹ýÑ¡Í¨ºó²Å»á½øÐÐÅÐ¶Ï

    //Á÷¿Ø
  input                 result,
  input                 result_en,
  output   reg [1:0]    out_port_num,
  output   reg          frame_length_en, //£¨Í¬Ê±Ò²ÓÃÓÚ¿ØÖÆ½ÚµãµØÖ·ÓÐÐ§£©
  output   reg  [10:0]  frame_length ,
  output   reg  [7:0]   node_flow_num,  //µØÖ·
  output   reg          lookup_fail,    //²é±íÊ§°Ü
  output   reg          class_flow_ctrl_en,   //ÕâÊÇ¸ù¾ÝÁ÷·ÖÀàµÄÐÅÏ¢µÃµ½µÄ
  output   reg [6:0]    class_flow_ctrl_num,   //ÕâÊÇ¸ù¾ÝÁ÷·ÖÀàµÄÐÅÏ¢µÃµ½µÄ
  output   reg          do_not_flow_ctrl

  );

    //==================Á÷¿ØÔö¼Ó==================
    reg [31:0] flow_fifo_data_in     ;   //Á÷¿ØFIFO£¬Ìæ´úrx_fifo_data
    (*mark_debug = "true"*) reg flow_fifo_wren           ;   //Á÷¿ØFIFO£¬Ìæ´úrx_fifo_wrreq
    (*mark_debug = "true"*) wire flow_fifo_full           ;   //Á÷¿ØFIFO
    (*mark_debug = "true"*) wire flow_fifo_empty          ;   //Á÷¿ØFIFO

    //=================FIFO´òÅÄ===================
    reg frame_info_fifo_empty_d1 ; //Íâ²¿Ö¡ÐÅÏ¢fifo¿Õ´òÅÄ
    reg flow_fifo_empty_d1 ; //Á÷¿Øfifo¿Õ´òÅÄ
    reg lookup_result_fifo_empty_d1 ; //²éÕÒ½á¹û¿Õ´òÅÄ

    reg[31:0] frame_info_fifo_o_d1 ; //Ö¡ÐÅÏ¢´òÅÄ£¨Íâ²¿£©
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) 
            frame_info_fifo_o_d1 <= 32'd0 ;
        else
            frame_info_fifo_o_d1 <= frame_info_fifo_o ;
    end

    reg flow_fifo_full_d1 ; //Á÷¿ØfifoÂú£¨ÄÚ²¿£©
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n)
            flow_fifo_full_d1 <= 1'b0 ;
        else
            flow_fifo_full_d1 <= flow_fifo_full ; 
    end

    reg rx_fifo_full_d1 ; //Íâ²¿fifoÂú
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n)
            rx_fifo_full_d1 <= 1'b0 ;
        else
            rx_fifo_full_d1 <= rx_fifo_full ; 
    end

    //===========================================

        //ÖØ¶¨ÏòÐÅºÅ
    //(*mark_debug = "true"*) wire do_not_flow_ctrl ;

    wire next_fifo_full ;
    assign next_fifo_full = flow_fifo_full_d1 ;    //ÏÂÒ»¸öfifoÎªÂú
    //============================================
   
 
//µÚÒ»¼¶Á÷Ë®,¸ù¾ÝÊäÈëÖ¡ÐÅÏ¢£¬½øÐÐ²é±í£¬²¢°Ñ¶ÔÓ¦Ö¡ÐÅÏ¢sour_port_idÐ´½øfp_info_fifo validÓÃ             
localparam LOOK_UP_IDLE            = 3'b000 ,  //¿ÕÏÐ
          UNI_MULTI_JUDGE         = 3'b001 ,  //ÅÐ¶Ïµ¥×é²¥
          UNI_LOOK_UP             = 3'b010 ,  //µ¥²¥²é±í
          MULTI_LOOK_UP           = 3'b100 ;  //×é²¥²é±í

//µÚ¶þ¼¶Á÷Ë®,¸ù¾Ý²é±íFIFO½á¹ûºÍ¶ÔÓ¦µÄÖ¡ÐÅÏ¢FIFOÊý¾ÝÒÔ¼°·Ö×é´¦ÀíµÄÐÅÏ¢fifoÐ´µ÷¶ÈÐÅÏ¢  
localparam WLOOKUP_IDLE            = 2'b00 ,   //¿ÕÏÐ
            READ_WAIT             = 2'b01 ,
            READ_INFO               = 2'b11 ,
            READ_INFO_REG           = 2'b10 ;


//state
(*mark_debug = "true"*) reg [2:0]  lookup_cstate  ;
(*mark_debug = "true"*) reg [2:0]  lookup_nstate  ;
(*mark_debug = "true"*) reg [1:0]  wlookup_cstate ;
(*mark_debug = "true"*) reg [1:0]  wlookup_nstate ;



//¼ÇÂ¼µÚÒ»¼¶Á÷Ë®ÖÐÖ¡ÐÅÏ¢,ÓÃÓÚ²é±í,»¹ÓÐÔ´¶Ë¿ÚºÅ
reg [  3:0] sou_id_reg      ; 
reg [ 47:0] sou_addr_reg    ; 
reg [ 47:0] des_addr_reg    ; 
reg         multicast_reg   ; 
reg [128:0] ip_src_addr_reg ; 
reg         access_fail_reg ;


//µÚÒ»¼¶²é±í½á¹ûFIFO
reg  [5:0] lookup_result_fifo_din  ; 
reg  lookup_result_fifo_wren       ;
reg  lookup_result_fifo_rden       ;
wire [5:0] lookup_result_fifo      ; 
wire lookup_result_fifo_full       ;
wire lookup_result_fifo_empty      ;      

reg [5:0] lookup_result_fifo_reg  ;         

//add 6/5
//reg [3:0] lookup_valid_cnt ;                      

    //=================FIFO´òÅÄ===================
    // reg frame_info_fifo_empty_d1 ;
    // reg flow_fifo_empty_d1 ;
    // reg lookup_result_fifo_empty_d1 ;
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            frame_info_fifo_empty_d1 <= 1'b1 ;
            flow_fifo_empty_d1 <= 1'b1 ;
            lookup_result_fifo_empty_d1 <= 1'b1 ;
        end
        else begin
            frame_info_fifo_empty_d1 <= frame_info_fifo_empty ;
            flow_fifo_empty_d1 <= flow_fifo_empty ;
            lookup_result_fifo_empty_d1 <= lookup_result_fifo_empty ;
        end
    end

    reg lookup_result_fifo_full_d1 ;//²éÕÒ½á¹ûÂú
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            lookup_result_fifo_full_d1 <= 1'b0 ;
        end
        else begin
            lookup_result_fifo_full_d1 <= lookup_result_fifo_full ;
        end
    end

    
    reg[5:0] lookup_result_fifo_d1 ; //²éÕÒ½á¹ûfifo
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            lookup_result_fifo_d1 <= 32'd0 ;
        end
        else begin
            lookup_result_fifo_d1 <= lookup_result_fifo ;
        end
    end
    //===========================================

//---------------------------------------------
//MAIN CODE
//---------------------------------------------
//¼ÇÂ¼emacÖ¡ÐÅÏ¢ 
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        ip_src_addr_reg <= 129'b0 ;
        access_fail_reg <= 1'b0   ;
        sou_addr_reg    <= 48'd0  ;
        des_addr_reg    <= 48'd0  ;
        sou_id_reg      <= 4'd0   ;
        multicast_reg   <= 1'b0   ;
    end
    else if (lookup_nstate == UNI_MULTI_JUDGE) begin
        access_fail_reg <= access_fail ;
        sou_addr_reg    <= sou_addr    ;
        des_addr_reg    <= des_addr    ;
        sou_id_reg      <= sou_id      ;
        multicast_reg   <= multicast   ;
        ip_src_addr_reg <= ip_src_addr ;
    end
end

//¸ø·Ö×é´¦ÀíµÄµ÷¶ÈÓ¦´ð
always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        wr_gnt  <= 1'b0;
    end
    else if (lookup_cstate == UNI_MULTI_JUDGE) begin
        wr_gnt  <= 1'b1;
    end
    else begin
        wr_gnt  <= 1'b0; 
    end
end

//************************************************************************
//******************************µÚÒ»¼¶Á÷Ë®********************************
//¸ù¾ÝÊäÈëÖ¡ÐÅÏ¢,½øÐÐ²é±í(access_fail²»ÓÃ²é±í),²¢°Ñ¶ÔÓ¦Ö¡ÐÅÏ¢Ð´½øfp_info_fifo 
//µÚÒ»¼¶Á÷Ë®,×´Ì¬»úµÚÒ»¶Î
always @ (posedge clk or negedge rst_n)
begin
    if(!rst_n)
        lookup_cstate <= LOOK_UP_IDLE;
    else
        lookup_cstate <= lookup_nstate;
end

//µÚÒ»¼¶Á÷Ë®,×´Ì¬»úµÚ¶þ¶Î
always @ ( * )
begin
    case(lookup_cstate)
        LOOK_UP_IDLE: begin //´¢´æÖ¡ÐÅÏ¢FIFOºÍ²é±í½á¹ûµÄFIFOÎ´Âú
            if( /*fp_info_fifo_full == 1'b0 &&*/ lookup_result_fifo_full_d1 == 1'b0 && in_buf_val == 1'b1 && unicam_init_done == 1'b1 && multicam_init_done == 1'b1 )
                lookup_nstate = UNI_MULTI_JUDGE ;
            else
                lookup_nstate = lookup_cstate ; 
        end 
        UNI_MULTI_JUDGE:begin 
            if(access_fail_reg == 1'b1)
                lookup_nstate = LOOK_UP_IDLE ;
            else if(uni_busy==1'b0 && multicast_reg==1'b0) //µ¥²¥²é±í
                lookup_nstate = UNI_LOOK_UP ;
            else if(multi_busy==1'b0 && multicast_reg==1'b1)//×é²¥²é±í
                lookup_nstate = MULTI_LOOK_UP ;
            else
                lookup_nstate = lookup_cstate ; //²é±íÄ£¿éÃ¦,×´Ì¬»úµÈ´ý
        end
        UNI_LOOK_UP: begin
            lookup_nstate = LOOK_UP_IDLE;
        end
        MULTI_LOOK_UP : begin
            lookup_nstate = LOOK_UP_IDLE;
        end
        default : begin
            lookup_nstate = LOOK_UP_IDLE;
        end
  endcase
end 

//***************************µ¥²¥²é±í**********************************
//Ê¹ÄÜ
// always @ (posedge clk or negedge rst_n) begin
//     if (!rst_n) begin
//         uni_addr_en <= 1'b0;
//     end
//     else if (lookup_nstate == UNI_LOOK_UP) begin
//         uni_addr_en <= 1'b1;
//     end
//     else begin
//         uni_addr_en <= 1'b0;
//     end
// end
//ËÙÂÊ²»¹»»»³É×éºÏÂß¼­
assign  uni_addr_en = (lookup_nstate == UNI_LOOK_UP)? 1'b1 : 1'b0 ;

//µ¥²¥²é±í
assign mac_sour  = sou_addr_reg ; 
assign mac_dest  = des_addr_reg ; 
assign port_sour = sou_id_reg   ; 

//***************************×é²¥²é±í**********************************
//Ê¹ÄÜ
/*always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        multi_addr_en <= 1'b0;
    end
    else if (lookup_nstate==MULTI_LOOK_UP) begin
        multi_addr_en <= 1'b1;
    end
    else begin
        multi_addr_en <= 1'b0;
    end
end*/

assign multi_addr_en = (lookup_nstate == MULTI_LOOK_UP)? 1'b1 : 1'b0 ;
//×é²¥²é±í
assign multi_ip_src_addr = ip_src_addr_reg ;

//Ð´²é±í½á¹û
//******************************lookup_result_fifo Éî¶È20*********************************
//change 6.4,²é±íÄ£¿é´æÔÚ³õÊ¼»¯,ÎªÁË·ÀÖ¹´íÎó,Ö»ÓÐ²é±í¹ý,²Å»áÐ´²é±í½á¹ûFIFO
// always @( posedge clk or negedge rst_n )
// begin 
//   if ( !rst_n )
//     lookup_valid_cnt <= 4'd0 ;
//   else if ( ( lookup_nstate ==  UNI_LOOK_UP || lookup_nstate == MULTI_LOOK_UP ) && ( uni_outport_en == 1'b1 || multi_outport_en == 1'b1 ) )
//     lookup_valid_cnt <= lookup_valid_cnt ;
//   else if ( lookup_nstate ==  UNI_LOOK_UP || lookup_nstate == MULTI_LOOK_UP )
//     lookup_valid_cnt <= lookup_valid_cnt + 4'd1 ;
//   else if ( ( uni_outport_en == 1'b1 || multi_outport_en == 1'b1 ) && lookup_valid_cnt >= 4'd1 )
//     lookup_valid_cnt <= lookup_valid_cnt - 4'd1 ;
//   else
//     lookup_valid_cnt <= lookup_valid_cnt ;
// end
 
//lookup_result_fifo_wren //change 6.4
always @( posedge clk or negedge rst_n)
begin
  if ( !rst_n )
    lookup_result_fifo_wren <= 1'b0 ;
  else if ( ( uni_outport_en == 1'b1 || multi_outport_en == 1'b1 ) && unicam_init_done == 1'b1 && multicam_init_done == 1'b1 /*lookup_valid_cnt > 4'd0*/ )
    lookup_result_fifo_wren <= 1'b1 ;
  else
    lookup_result_fifo_wren <= 1'b0 ;
end 

//lookup_result_fifo_din |[5] multi/uni| |[4] valid| |[3:0] multi_outport/uni_outport|
always @( posedge clk or negedge rst_n )
begin
  if ( !rst_n )
      lookup_result_fifo_din <= 6'd0 ;
  else if ( uni_outport_en == 1'b1 )  
      if ( uni_lookup_fail  == 1'b1 )
          lookup_result_fifo_din <= { 1'b0 , 1'b0 , 4'b0 } ;
      else
          lookup_result_fifo_din <= { 1'b0 , 1'b1 , uni_outport } ;
  else if ( multi_outport_en == 1'b1 )
      lookup_result_fifo_din <= { 1'b1 , 1'b1 , multi_outport } ;
  else 
      lookup_result_fifo_din <= 6'd0 ;
end 

//lookup_result_fifo_rden
always @( posedge clk or negedge rst_n) begin
    if (!rst_n)
        lookup_result_fifo_rden <= 1'b0 ;
    else if (wlookup_nstate==READ_INFO)
        lookup_result_fifo_rden <= 1'b1 ;
    else
        lookup_result_fifo_rden <= 1'b0 ;
end
    
//lookup_result_fifo_reg
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        lookup_result_fifo_reg <= 6'b0 ;
    end
    else if (wlookup_nstate==READ_INFO) begin
        lookup_result_fifo_reg <= lookup_result_fifo_d1 ;
    end
    else begin
        lookup_result_fifo_reg <= lookup_result_fifo_reg ;
    end
end
//*************************************************************************** 



//******************************µÚ¶þ¼¶Á÷Ë®********************************
//¸ù¾Ý²é±íFIFO½á¹ûºÍ¶ÔÓ¦µÄÖ¡ÐÅÏ¢FIFOÊý¾ÝÐ´Ö¡½á¹û 
//µÚ¶þ¼¶Á÷Ë®,×´Ì¬»úµÚÒ»¶Î
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        wlookup_cstate <= WLOOKUP_IDLE;
    else
        wlookup_cstate <= wlookup_nstate;
end
//********************************    
//×¢£º²»¿¼ÂÇrx_fifo_fullÂúµÄÇå¿öÏÂ,µÚ¶þ¼¶µÄÁ÷Ë®µÄËÙ¶ÈÊ¼ÖÕ»á¿ìÓÚµÚÒ»¼¶Á÷Ë®,ËùÒÔÈç¹ûrx_fifo²»»áÂúµÄÇé¿öÏÂ,²é±í½á¹û¿ÉÒÔ²»ÓÃÐ´½øfifoÀï£¬ÕâÑù»á¸ü¿ì£¬ÇÒfp_fifoÉî¶È¿ÉÒÔÉèÖÃµÄ·Ç³£Ð¡
always @ ( * )
begin   
  case ( wlookup_cstate ) 
    WLOOKUP_IDLE : begin
      if ( lookup_result_fifo_empty_d1 == 1'b0 && frame_info_fifo_empty_d1 == 1'b0 &&  next_fifo_full == 1'b0 ) begin
        wlookup_nstate =  READ_WAIT ;
      end 
      else begin
        wlookup_nstate = wlookup_cstate ;
      end      
    end
    READ_WAIT : begin
        wlookup_nstate =  READ_INFO ;
    end
    READ_INFO : begin
      wlookup_nstate = READ_INFO_REG ;
    end
    READ_INFO_REG : begin
      /*if ( frame_info_fifo_o[14] == 1'b0 || ( lookup_result_fifo_reg[18] == 1'b0 && frame_info_fifo_o[32] == 1'b0 ) ||
                               ( frame_info_fifo_0[15] == 1'b1 && frame_info_fifo_o[14] == 1'b0 ) ) begin  //Á÷·ÖÀà¶ªÆú¡¢·Ç²åÈëÖ¡²é±íÊ§°Ü¡¢·Ç¸´ÖÆÖØ¶¨Ïò
        wlookup_nstate = DELT ;
      end
      else if ( frame_info_fifo_o[32] == 1'b1 ) begin
        wlookup_nstate = INSERT ;
      end 
      else begin
        wlookup_nstate = WRITE ;
      end*/
      wlookup_nstate = WLOOKUP_IDLE ;
    end
    /*DELT : begin
      wlookup_nstate = WLOOKUP_IDLE;
    end
    INSERT: begin
      wlookup_nstate = WLOOKUP_IDLE;
    end
    WRITE: begin
      wlookup_nstate = WLOOKUP_IDLE;
    end*/
    default: begin
      wlookup_nstate = WLOOKUP_IDLE;
    end
    endcase
end


//frame_info_fifo_rden
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        frame_info_fifo_rden <= 1'b0 ;
    end
    else if (wlookup_nstate==READ_INFO) begin
        frame_info_fifo_rden <= 1'b1 ;
    end
    else begin
        frame_info_fifo_rden <= 1'b0 ;
    end
end


/*//frame_info_fifo_o_reg
always @(posedge clk or negedge rst_n) begin
  if (!rst_n) begin
    frame_info_fifo_o_reg <= 33'b0 ;
  end
  else if ( wlookup_cstate == READ_INFO_REG ) begin //frame_info_fifo_rden_dl1 == 1'b1
    frame_info_fifo_o_reg <= frame_info_fifo_o ;
  end
  else begin
    frame_info_fifo_o_reg <= frame_info_fifo_o_reg ;
  end
end*/
       
//--------------------------
//µ÷¶È½á¹ûFIFO
//--------------------------
//assign frame_info_o = (frame_info_fifo_wren)?{insert_frame_flag,insert_dest_node,is_flow_ctrl_r,flow_ctrl_num,valid_bit,pri,frame_length_r}:32'h0;
//|[31] insert_flag| |[30:23] insert_port| |[22] flow_en| |[21:15] flow_num| |[14] valid| |[13:11] pri| |[10:0] len| | 
////rx_fifo
// _ _ _ 4 _ _  _ _ _ 4 _ _ _ _ _ _ _4 _ _ _ _ _  _ 4 _ _ _ _ _ 3 _ _ _ _ _ 11 _ _ _  _ _ _ 2 _ _ _  _ _ 4_ _ _
//|    31~29   |    28    |      27~24    |     23~20     |  19~17 |     16~6     |      5~4     |    3~0    |
//|___reserve__|___discard__|___sour_port___|___dest_port___|___pri__|_frame_length_|__frame_type__|__buf_num__|

always @(posedge clk or negedge rst_n) begin 
  if (!rst_n) begin
    flow_fifo_data_in <= 32'b0 ;
  end
  else if ( wlookup_nstate == READ_INFO_REG ) begin  //ºóÐø¿ÉÒÔÔÚÕâÀï¼ÓÈëÁ÷¿Ø£¬Á÷¿ØÊ§°ÜÔòÐ´ÎÞÐ§µ÷¶ÈÐÅÏ¢
      if ( frame_info_fifo_o_d1[14] == 1'b0 || ( lookup_result_fifo_reg[4] == 1'b0 && frame_info_fifo_o_d1[31] == 1'b0 )  ) //Á÷·ÖÀà¶ªÆú¡¢·Ç²åÈëÖ¡²é±íÊ§°Ü 
          flow_fifo_data_in <= {3'b0 , 1'b1 , 28'b0} ;

      else if ( frame_info_fifo_o_d1[31] == 1'b1 ) begin //²åÈëÖ¡ 
          if ( frame_info_fifo_o_d1[26:23] == 4'b1111 )
              flow_fifo_data_in <= {3'b0,1'b0,4'b0,frame_info_fifo_o_d1[26:23],frame_info_fifo_o_d1[13:11],frame_info_fifo_o_d1[10:0],2'b11,4'b0 } ;
          else if ( frame_info_fifo_o_d1[26] + frame_info_fifo_o_d1[25] + frame_info_fifo_o_d1[24] + frame_info_fifo_o_d1[23] == 4'd1 )
              flow_fifo_data_in <= {3'b0,1'b0,4'b0,frame_info_fifo_o_d1[26:23],frame_info_fifo_o_d1[13:11],frame_info_fifo_o_d1[10:0],2'b00,4'b0 } ;
          else  
              flow_fifo_data_in <= {3'b0,1'b0,4'b0,frame_info_fifo_o_d1[26:23],frame_info_fifo_o_d1[13:11],frame_info_fifo_o_d1[10:0],2'b10,4'b0 } ;
      end 

      else begin
          if ( lookup_result_fifo_reg[3:0] == 4'b1111 )   //ÆÕÍ¨Ö¡ÐèÒª¸ù¾ÝÊäÈëµÄÖ¡ÀàÐÍºÍ²é±í½á¹ûÌîÐ´Ö¡ÀàÐÍÇøÓò
              flow_fifo_data_in <= {3'b0,1'b0,4'b0,lookup_result_fifo_reg[3:0],frame_info_fifo_o_d1[13:11],frame_info_fifo_o_d1[10:0],2'b11,4'b0 } ;//¹ã²¥
          else if ( lookup_result_fifo_reg[5] == 1'b1 )
              flow_fifo_data_in <= {3'b0,1'b0,4'b0,lookup_result_fifo_reg[3:0],frame_info_fifo_o_d1[13:11],frame_info_fifo_o_d1[10:0],2'b10,4'b0 } ;//×é²¥
          else 
              flow_fifo_data_in <= {3'b0,1'b0,4'b0,lookup_result_fifo_reg[3:0],frame_info_fifo_o_d1[13:11],frame_info_fifo_o_d1[10:0],2'b00,4'b0 } ;//µ¥²¥
      end 
     //flow_fifo_data_in <= {3'b0,1'b1,4'b0,lookup_result_fifo_reg[3:0],frame_info_fifo_o_d1[13:11],frame_info_fifo_o_d1[10:0],2'b0,4'b0 } ;
  end
  else  
    flow_fifo_data_in <= 32'b0;
end

//
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        flow_fifo_wren <= 1'b0 ;
    end
    else if (wlookup_nstate==READ_INFO_REG) begin
        flow_fifo_wren <= 1'b1 ;
    end
    else begin
        flow_fifo_wren <= 1'b0 ;
    end
end


//******** lookup_result_fifo 6bts Ê××ÖÖÃ³ö
//********|[5] multi/uni| |[4] valid| |[3:0] multi_outport/uni_outport|
`ifdef ASIC
lookup_result_fifo_fwft U_lookup_result_fifo_asic(
    .clk(clk),
    .clr(rst_n),
    .ram_2p_cfg_register(ram_2p_cfg_register),                      
    .w_data(lookup_result_fifo_din),
    .w_we(lookup_result_fifo_wren),
    .w_full(lookup_result_fifo_full),
    .w_afull(),
                          
    .r_data(lookup_result_fifo),
    .r_re(lookup_result_fifo_rden),
    .r_empty(lookup_result_fifo_empty),
    .r_aempty()
);
`else
lookup_result_fifo_ip U_lookup_result_fifo (
  .rst  (~rst_n                  ),
  .clk  (clk                     ), // input clk
  .din  (lookup_result_fifo_din  ), // input [5 : 0] din
  .wr_en(lookup_result_fifo_wren ), // input wr_en
  .rd_en(lookup_result_fifo_rden ), // input rd_en6
  .dout (lookup_result_fifo      ), // output [5 : 0] dout
  .full (lookup_result_fifo_full ), // output full
  .empty(lookup_result_fifo_empty)  // output empty
);
`endif





//=======================================================================================================================================
// flow ctrl fifo
    wire flow_fifo_wr_wire ;
    assign flow_fifo_wr_wire = flow_fifo_wren ;

    reg flow_fifo_rden ;
    wire[31:0] flow_fifo_data_out ;
    reg[31:0] flow_fifo_data_out_d1 ;

    always @(posedge clk or negedge rst_n) begin
        if( !rst_n ) 
            flow_fifo_data_out_d1 <= 32'b0 ;
        else 
            flow_fifo_data_out_d1 <= flow_fifo_data_out ;
    end

    `ifdef ASIC
        wire flow_fifo_almost_full;
        flow_ctrl_fifo u_flow_ctrl_fifo(
        .clock          ( clk          ),
        .rst_n          ( rst_n          ),
        .ram_2p_cfg_register(ram_2p_cfg_register),
        .fifo_wen       ( flow_fifo_wr_wire       ),
        .fifo_wdata     ( flow_fifo_data_in     ),

        .fifo_ren       ( flow_fifo_rden       ),
        .fifo_rdata     ( flow_fifo_data_out     ),
        .fifo_full_wr   ( flow_fifo_full   ),
        .fifo_empty_rd  ( flow_fifo_empty  ),
        .almost_full    ( flow_fifo_almost_full    ) ,
        .r_aempty       ()
    );

        `else
        flow_ctrl_fifo U_flow_ctrl_fifo (
            .rst  (~rst_n                  ),
            .clk  (clk                     ), // input clk
            .din  (flow_fifo_data_in /*declare above*/  ), // input [31 : 0] din()
            .wr_en(flow_fifo_wr_wire /*declare above*/ ), // input wr_en
            .rd_en(flow_fifo_rden ), // input rd_en6
            .dout (flow_fifo_data_out      ), // output [31 : 0] dout
            .full (flow_fifo_full /*declare above*/ ), // output full()
            .empty(flow_fifo_empty /*declare above*/ )  // output empty()
        ) ;
    `endif

// output signal
    //判断是否需要流控（out_port_num信号）
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            out_port_num <= 2'b00 ; //2'b00表示不流控，2'b01表示要流控
        end
        else if( wlookup_nstate == READ_WAIT /*需要根据之前的结果来决定是否需要启用流控功能*/ ) begin
            out_port_num <= 2'b01 ;
        end
        else 
            out_port_num <= 2'b00 ;
    end

    //帧长信息
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            frame_length_en <= 1'b0 ;
            frame_length <= 11'b000_0000_0000 ;
        end
        else if( wlookup_nstate == READ_WAIT ) begin
            frame_length_en <= 1'b1 ;
            frame_length <= frame_info_fifo_o[10:0] ;
        end
        else begin
            frame_length_en <= 1'b0 ;
            frame_length <= frame_length ;
        end
    end

    //查表结果（ "帧长有效"信号 同时也用于 "查表结果有效" 信号 ）
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            lookup_fail <= 1'b0 ;
            node_flow_num <= 8'b0000_0000 ;
        end
        else if( wlookup_nstate == READ_WAIT ) begin
            lookup_fail <= (~lookup_result_fifo[4]) ;
            node_flow_num <= { 4'b0000, lookup_result_fifo[3:0] } ;
        end
        else begin
            lookup_fail <= lookup_fail ;
            node_flow_num <= node_flow_num ;
        end
    end

    //流分类结果
    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            class_flow_ctrl_en <= 1'b0 ;
            class_flow_ctrl_num <= 7'b000_0000 ;
        end
        else if( wlookup_nstate == READ_WAIT ) begin
            class_flow_ctrl_en <= 1'b1 ;
            class_flow_ctrl_num <= frame_info_fifo_o[21:15] ;
        end
        else begin
            class_flow_ctrl_en <= 1'b0 ;
            class_flow_ctrl_num <= class_flow_ctrl_num ;
        end
    end

    always@(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            do_not_flow_ctrl <= 1'b0 ;
        end
        else if( wlookup_nstate == READ_WAIT ) begin
            do_not_flow_ctrl <= (!frame_info_fifo_o[22]) ;
        end
    end

// FSM
    reg [1:0] flow_ctrl_cstate ;
    reg [1:0] flow_ctrl_nstate ;

    parameter FC_IDLE  = 2'b00;
    parameter FC_WRITE = 2'b01;
    parameter FC_WAIT1 = 2'b11;
    parameter FC_WAIT2 = 2'b10;

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)
            flow_ctrl_cstate <= FC_IDLE ;
        else
            flow_ctrl_cstate <= flow_ctrl_nstate ;
    end

    always @( * ) begin
        case (flow_ctrl_cstate)
            FC_IDLE: begin
                if( result_en && !flow_fifo_empty_d1 && !rx_fifo_full )
                    flow_ctrl_nstate = FC_WRITE ;
                else 
                    flow_ctrl_nstate = FC_IDLE ;
            end

            FC_WRITE: flow_ctrl_nstate = FC_WAIT1 ;

            FC_WAIT1: flow_ctrl_nstate = FC_WAIT2 ;

            FC_WAIT2: flow_ctrl_nstate = FC_IDLE ;

            default: flow_ctrl_nstate = FC_IDLE ;
        endcase
    end

// FSM_3
    reg result_r ;
    always @(posedge clk or negedge rst_n) begin
        if( !rst_n )
            result_r <= 1'b1 ;
        else if( result_en )
            result_r <= result ;
    end

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)
            flow_fifo_rden <= 1'b0 ;
        else if( flow_ctrl_nstate == FC_WRITE )
            flow_fifo_rden <= 1'b1 ;
        else 
            flow_fifo_rden <= 1'b0 ;
    end

    reg [31:0]  rx_fifo_data_r ;
    reg         rx_fifo_wrreq_r ;

    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            rx_fifo_data_r <= 32'b0 ;
            rx_fifo_wrreq_r <= 1'b0 ;
        end
        else if( flow_ctrl_nstate == FC_WRITE ) begin
            rx_fifo_data_r <= {flow_fifo_data_out[31:29], (flow_fifo_data_out[28] | (~result)), flow_fifo_data_out[27:0] } ;
            rx_fifo_wrreq_r <= 1'b1 ;
        end
        else begin
            rx_fifo_data_r <= 32'b0 ;
            rx_fifo_wrreq_r <= 1'b0 ;
        end
    end

    assign rx_fifo_data = rx_fifo_data_r ;
    assign rx_fifo_wrreq = rx_fifo_wrreq_r ;

//=======================================================================================================================================
endmodule




